#include "databasequeue.h"
#include <QDebug>
#include <assert.h>
#include <QFile>

DatabaseQueue * DatabaseQueue::m_instance=NULL;

DatabaseQueue *DatabaseQueue::instance()
{
    if(m_instance == nullptr){
        m_instance = new DatabaseQueue();
    }
    return m_instance;
}

DatabaseQueue::DatabaseQueue(QObject *parent) : QObject(parent)
{
    qRegisterMetaType<std::function<void()>>("std::function<void()>");
    m_thread = new QThread;
    this->moveToThread(m_thread);
    m_thread->start();
    connect(this,&DatabaseQueue::createDatabaseConnection
            ,this,&DatabaseQueue::createDatabaseConnectionSlot,Qt::QueuedConnection);
}

QSqlQuery DatabaseQueue::execSql(const QString &sql)
{
    QSqlQuery t_query(m_database);
    qDebug()<<"[DatabaseQueue] sql:"<<sql<<QThread::currentThreadId();
    SqlQueue queue;
    queue.sql = sql;
    ///阻塞当前线程
    QSemaphore m_syncSemaphore;
    queue.callback = [&](const QSqlQuery &queue){
        t_query = queue;
        m_syncSemaphore.release();
    };
    m_highPQMutex.lock();
    m_highPriorityQueue.enqueue(queue);
    m_highPQMutex.unlock();

    ///释放给数据库队列执行
    m_semaphore.release();

    m_syncSemaphore.acquire();

    return t_query;
}

void DatabaseQueue::execAsyncSql(const QString &sql)
{
    SqlQueue queue;
    queue.sql = sql;

    m_lowPQMutex.lock();
    m_lowPriorityQueue.enqueue(queue);
    m_lowPQMutex.unlock();
    m_semaphore.release();
}

void DatabaseQueue::execSql(const SqlQueue &queue)
{
    m_lowPQMutex.lock();
    m_lowPriorityQueue.enqueue(queue);
    m_lowPQMutex.unlock();
    m_semaphore.release();
}

void DatabaseQueue::stop()
{
    m_running = false;

    m_highPQMutex.lock();
    QSqlQuery query;
    foreach(SqlQueue queue,m_highPriorityQueue){
        queue.callback(query);
    }
    m_highPriorityQueue.clear();
    m_highPQMutex.unlock();

    m_lowPQMutex.lock();
    m_lowPriorityQueue.clear();
    m_lowPQMutex.unlock();

    if(m_semaphore.available()>0)
        m_semaphore.acquire(m_semaphore.available());
    m_semaphore.release();

    QMutexLocker locker(&m_dbMutex);
//    if(m_database){
//        QString name = m_database->connectionName();
//        m_database->close();
//        delete  m_database;
//        m_database = nullptr;
//        QSqlDatabase::removeDatabase(name);
//    }
}

void DatabaseQueue::createDatabaseConnectionSlot()
{
//    m_database = new QSqlDatabase();
    connectDatabase();
    qDebug()<<"[DatabaseQueue::ready to run]";
    m_running = true;
    dealQueue();
}

void DatabaseQueue::connectDatabase()
{
    // 1. 加载 SQLite 数据库驱动
    m_database = QSqlDatabase::addDatabase("QSQLITE", "Connection");
    QFile file("assets:/gocampus.db");
    if(file.exists()){
        qDebug()<<"数据库文件存在！";
        QFile file1("/storage/emulated/0/data/gocampus.db");
        if(file1.exists())
            file1.remove();
        QFile::copy("assets:/gocampus.db","/storage/emulated/0/data/gocampus.db");
        file.setPermissions(QFile::ReadUser  | QFile::WriteUser);
    }
    // 2. sqlitedata.db 是 SQLite 的数据库文件名
    //    如果此文件不存在则自动创建，如果已经存在则使用已经存在的文件
    m_database.setDatabaseName("/storage/emulated/0/data/gocampus.db");

    // 3. 打开数据库连接，成功返回 true，不成功则程序退出
    if (!m_database.open()) {
        qDebug() << "Connect to Sqlite error: " << m_database.lastError().text();
        exit(128);
    }
//    // 6. 查询刚才插入的数据
//    QSqlQuery selectQuery(m_database);
//    selectQuery.exec("SELECT * FROM user");

//    while (selectQuery.next()) {
//        qDebug() << QString("name: %1, sex: %2, phone: %3")
//                    .arg(selectQuery.value("user_name").toString())
//                    .arg(selectQuery.value("user_sex").toString())
//                    .arg(selectQuery.value("user_phone").toString());
//    }
}

void DatabaseQueue::dealQueue()
{
    qDebug()<<"[DatabaseQueue::dealQueue] start";
    while(m_running){
        m_semaphore.acquire();
        if(!m_running){
            qDebug()<<"[DatabaseQueue::dealQueue] quit";
            return ;
        }
        SqlQueue queue;

        ///先处理高队列
        if(!queue.isValid){
            QMutexLocker locker(&m_highPQMutex);
            if(!m_highPriorityQueue.isEmpty()){
                queue = m_highPriorityQueue.dequeue();
                queue.isValid = true;
            }
        }
        if(!queue.isValid){
            QMutexLocker locker(&m_lowPQMutex);
            if(!m_lowPriorityQueue.isEmpty()){
                queue = m_lowPriorityQueue.dequeue();
                queue.isValid = true;
            }
        }
        if(queue.isValid){
            ///执行并回调
            QMutexLocker locker(&m_dbMutex);
            QSqlQuery query(m_database);
            qDebug()<<"DatabaseQueue::dealQueue:"<<queue.sql;
//            assert(query.isValid());
            if(!query.exec(queue.sql)){
                reportSqlError(query);
            }
            queue.callback(query);
        }else{
            qDebug()<<"DatabaseQueue::dealQueue error:"<<queue.sql;
        }
    }
}

void DatabaseQueue::reportSqlError(QSqlQuery &query)
{
    qDebug()<<"ERROR:"<< query.lastError().text()<<" DataBase: sql:"<<query.lastQuery();
}
